﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ACSR.SqlServer.AddIn.Core.Interface;
using EnvDTE;
using ACSR.PythonScripting;
using System.IO;
using ACSR.Controls.ThirdParty.Python;
using ACSR.SqlServer.AddIn.Core.Interfaces;
using PyAddIn.Adapters;
using ACSR.SqlServer.AddIn.Core.Controllers;
using Extensibility;

namespace PyAddIn.Controllers
{
    public class PythonAddinController : AddInController
    {
        IAddInAdapter _adapter;

        IToolWindowContext _debuggerHostWindow;

        dynamic _handler;

        public PythonAddinController(object addinInst)
            : base(addinInst)
        {
            _adapter = new AddInAdapter(this);
            _adapter.OnMessage += new AddInMessageEvent(_adapter_OnMessage);
            _adapter.OnError += new AddInMessageEvent(_adapter_OnError);
            _adapter.OnWarning += new AddInMessageEvent(_adapter_OnWarning);
            //_adapter.OnBeforeExecute += new _dispCommandEvents_BeforeExecuteEventHandler(_adapter_OnBeforeExecute);
           // _adapter.OnAfterExecute += new _dispCommandEvents_AfterExecuteEventHandler(_adapter_OnAfterExecute);
            _adapter.OnScriptReload += new EventHandler(_adapter_OnScriptReload);

            _adapter.CommonUIAssemblyLocation = UIDll; // _uiDLL;

        }

        ScriptMonitor _monitor;

        void _monitor_OnScriptUnLoading(object sender, ScriptMonitorEventArgs e)
        {
            try
            {

                _handler.UnhookEvents(this);
            }
            catch (Exception x)
            {
                LogError("Error _monitor_OnScriptUnLoading: " + x.Message);
            }
        }

        protected override void InternalOnConnectionCompleted()
        {
            InitDebuggerWindow();
            LoadScriptEngine();

            try
            {
                _handler.OnConnection(_adapter);
            }
            catch (Exception e)
            {
                LogError("Error _handler.OnConnection: " + e.Message);
            }

        }

        protected override void InternalQueryStatus(string CmdName, vsCommandStatusTextWanted NeededText, ref vsCommandStatus StatusOption, ref object CommandText)
        {
            try
            {

                dynamic results = _handler.QueryStatus(CmdName, NeededText, StatusOption, CommandText);
                StatusOption = results[0];
                CommandText = results[1];
                return;
            }
            catch (Exception e)
            {
                LogError("Error _handler.QueryStatus: " + e.Message);
            }

        }

        protected override void InternalExec(string CmdName, vsCommandExecOption ExecuteOption, ref object VariantIn, ref object VariantOut, ref bool Handled)
        {
            try
            {
                _handler.Exec(CmdName, ExecuteOption, VariantIn, VariantOut, Handled);
            }
            catch (Exception e)
            {
                LogError("Error _handler.Exec: " + e.Message);
            }
        }

        protected override void InternalOnBeginShutdownCompleted(ref Array custom)
        {
            try
            {
                _handler.OnBeginShutdown(custom);
            }
            catch (Exception e)
            {
                LogError("Error _handler.OnBeginShutdown: " + e.Message);
            }
        }

        protected override void InternalOnStartupCompleteCompleted(ref Array custom)
        {
            try
            {
                _debuggerHostWindow.Window.Visible = true;
                _handler.OnStartupComplete(custom);
            }
            catch (Exception e)
            {
                LogError("Error _handler.OnStartupComplete: " + e.Message);
            }

        }

        protected override void InternalOnAddInsUpdateCompleted(ref Array custom)
        {
            try
            {
                _handler.OnAddInsUpdate(custom);
            }
            catch (Exception e)
            {
                LogError("Error _handler.OnAddInsUpdate: " + e.Message);
            }

        }

        protected override void InternalOnDisconnectionCompleted(ext_DisconnectMode disconnectMode, ref Array custom)
        {
            try
            {
                _handler.OnDisconnection(disconnectMode, ref custom);
            }
            catch (Exception e)
            {
                LogError("Error _handler.OnDisconnection: " + e.Message);
            }

        }

        void _monitor_OnScriptLoading(object sender, ScriptMonitorEventArgs e)
        {
            try
            {
             //   e.Context.SetVariable("ObjectExplorer", _objectExplorer);
            }
            catch (Exception x)
            {
                LogError("Error _monitor_OnScriptLoading: " + x.Message);
            }


        }

        void _monitor_OnEngineMessage(object sender, string Message)
        {
            LogMessage(Message);
        }

        void LoadScriptEngine()
        {
            try
            {

                if (_monitor == null)
                {
                    var scriptDirectory = Path.Combine(this.WorkingDirectory, "Scripts");
                    var scriptFileName = Path.Combine(scriptDirectory, "SSMSAddin.py");
                    _monitor = new ScriptMonitor(scriptFileName);

                    _monitor.OnScriptLoading += new ScriptMonitorEvent(_monitor_OnScriptLoading);
                    _monitor.OnScriptLoaded += new ScriptMonitorEvent(_monitor_OnScriptLoaded);
                    _monitor.OnScriptUnLoading += new ScriptMonitorEvent(_monitor_OnScriptUnLoading);
                    _monitor.OnEngineMessage += new MessageEvent(_monitor_OnEngineMessage);
                    _monitor.Activate();

                }
            }
            catch (Exception x)
            {
                LogError("Error LoadScriptEngine: " + x.Message);
            }
        }

        void _monitor_OnScriptLoaded(object sender, ScriptMonitorEventArgs e)
        {
            try
            {

                LogMessage("Script loading...");
                _handler = e.Context.Scope.CreateDefaultConsumer();
                _handler.HookEvents(_adapter);
                LogMessage("Script Loaded");
            }
            catch (Exception x)
            {
                LogError("Error _monitor_OnScriptLoaded: " + x.Message);
            }
        }

        private void InitDebuggerWindow()
        {
            try
            {
                var pypad = new UcPyPad();
                pypad.ActiveWindow.Presenter.SetVariable("Controller", this);
                pypad.ActiveWindow.Presenter.SetVariable("Adapter", _adapter);
                _debuggerHostWindow = _adapter.CreateHostWindow(pypad, "IronPython Interactive", "E6AD7E34-34CA-47E7-95EE-7C05D4128580");

            }
            catch (Exception e)
            {
                LogError("Error InitDebuggerWindow: " + e.Message);
            }
        }


        protected override void InternalCommandEvents_AfterExecute(string Guid, int ID, object CustomIn, object CustomOut)
        {
            try
            {

                _handler.CommandEvents_AfterExecute(Guid, ID, CustomIn, CustomOut);
            }
            catch (Exception e)
            {
                LogError("Error _handler.CommandEvents_AfterExecute: " + e.Message);
            }
        }

        protected override void InternalCommandEvents_BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
        {
            try
            {
                _handler.CommandEvents_BeforeExecute(Guid, ID, CustomIn, CustomOut, ref CancelDefault);
            }
            catch (Exception e)
            {
                LogError("Error _handler.CommandEvents_BeforeExecute: " + e.Message);
            }
        }

        

        void _adapter_OnScriptReload(object sender, EventArgs e)
        {
            this.LoadScriptEngine();
            LogMessage("Script Reloaded");
        }

        void _adapter_OnWarning(object sender, string message, MessageType messageType)
        {
            LogWarning(message);
        }

        void _adapter_OnError(object sender, string message, MessageType messageType)
        {
            LogError(message);
        }

        void _adapter_OnMessage(object sender, string message, MessageType messageType)
        {
            LogMessage(message);
        }
    }
}
